package com.fruit.service.promotion.impl;

import com.fruit.pojo.promotion.UserInfo;
import com.joe.utils.cluster.ClusterManager;
import com.joe.utils.cluster.redis.RedisBaseConfig;
import com.joe.utils.common.StringUtils;
import com.joe.utils.function.LockExecFunction;
import com.joe.utils.function.TransactionFunction;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.stream.Collectors;

/**
 * 分销关系缓存引用
 * <p>
 * <strong>初始化的时候请调用{@link #beginInit() beginInit}方法来开始初始化，初始化结束后请调用{@link #commitInit() commitInit}来结束初始化</strong>
 * <p>
 * 从数据库中往当前缓存增加数据先使用{@link #addData(Collection, boolean) addData}或者
 * {@link #addData(Map, boolean) addData}或者{@link #batchPut(Map, boolean) batchPut}来添加数据
 * <p>
 * 加完毕后调用{@link #init() init}方法来构建链接、重构缓存
 * <p>
 * 因为开启了二级缓存:
 * <ul>
 * <li>所有从缓存取的操作都要通过{@link #convert(int) convertToOrder}方法或者{@link #convert(Collection) convert取列表}方法取</li>
 * <li>所有放入缓存的操作都通过{@link #putCache(int, Node, boolean) putCache}方法放入</li>
 * </ul>
 * <p>
 * 当需要插入一个根节点时，可以调用{@link #create(UserInfo) create}来创建，也可以调用{@link #addData(Collection, boolean)} addData}
 * 或者{@link #addData(Map, boolean)}  addData}来创建，与初始化不同的是，此处调用完addData后不需要调用{@link #init() init}
 * 来构建链接、重构缓存
 *
 * @author joe
 * @version 2018.04.17 17:26
 */
@Slf4j
public class TreeCache implements LockExecFunction {
    /**
     * 缓存池
     */
    private static Map<CacheKey, TreeCache> cache = new HashMap<>();
    private static int BATCH_NUM = 300;
    /**
     * 默认缓存名
     */
    public static String CACHE_NAME = "APP_TREE_CACHE_";
    /**
     * 锁名
     */
    private static String LOCK_NAME = "APP_TREE_CACHE_LOCK";
    /**
     * 默认下级数量
     */
    private static int MAX_CHILDS = 2;
    /**
     * 默认比较器
     */
    public static Comparator<UserInfo> COMPARATOR = (info1, info2) -> {
        int result = info1.getAllChilds().size() - info2.getAllChilds().size();

        if (result == 0) {
            result = info1.getSalesVolume().compareTo(info2.getSalesVolume());
        }
        
        if (result == 0 && info1.getTime() != null && info2.getTime() != null) {
            result = info1.getTime().compareTo(info2.getTime());
        }

        return result;
    };
    /**
     * 本地节点缓存
     */
    private transient Map<Integer, Node> localCache = new HashMap<>();
    /**
     * 缓存表
     */
    public transient Map<Integer, Node> userInfoMap;
    /**
     * 子节点最大值
     */
    private int maxChilds;
    /**
     * 比较器
     */
    private transient Comparator<UserInfo> comparator;
    /**
     * 分布式管理器
     */
    private transient ClusterManager clusterManager;
    /**
     * 缓存名
     */
    private String cacheName;
    /**
     * 缓存锁，初始化的时候锁定
     */
    private transient ReadWriteLock lock;
    /**
     * 活动ID
     */
    private String activityId;

    private TreeCache() {

    }

    /**
     * 获取实例
     *
     * @param config redis配置
     * @param id     活动ID
     * @return TreeCache实例
     */
    public static TreeCache getInstance(RedisBaseConfig config, String id) {
        return getInstance(config, 0, null, id);
    }

    /**
     * 获取实例
     *
     * @param config     redis配置
     * @param maxChilds  最大下级，默认3
     * @param comparator 比较器
     * @param id         活动id
     * @return TreeCache实例
     */
    public static TreeCache getInstance(RedisBaseConfig config, int maxChilds, Comparator<UserInfo> comparator,
                                        String id) {
        String cacheName = StringUtils.isEmpty(id) ? CACHE_NAME : CACHE_NAME + id;
        String lockName = StringUtils.isEmpty(cacheName) ? LOCK_NAME : cacheName + "_LOCK";
        CacheKey key = new CacheKey(config, cacheName);
        if (!cache.containsKey(key)) {
            synchronized (cache) {
                if (!cache.containsKey(key)) {
                    TreeCache treeCache = new TreeCache();
                    treeCache.clusterManager = ClusterManager.getInstance(config);
                    treeCache.userInfoMap = treeCache.clusterManager.getMap(cacheName);
                    treeCache.maxChilds = maxChilds <= 0 ? MAX_CHILDS : maxChilds;
                    treeCache.comparator = comparator == null ? COMPARATOR : comparator;
                    treeCache.cacheName = cacheName;
                    treeCache.activityId = id;
                    treeCache.lock = treeCache.clusterManager.getReadWriteLock(lockName);
                    cache.put(key, treeCache);
                }
            }
        }
        return cache.get(key);
    }

    /**
     * 开始初始化
     */
    public void beginInit() {
        getLock().writeLock().lock();
    }

    /**
     * 结束初始化
     */
    public void commitInit() {
        getLock().writeLock().unlock();
    }

    /**
     * 初始化前调用，添加用户信息
     *
     * @param userInfoList 要添加的用户信息
     * @param flush        是否立即刷新
     */
    public void addData(Collection<UserInfo> userInfoList, boolean flush) {
        Map<Integer, Node> waitAdd = new HashMap<>();

        for (UserInfo userInfo : userInfoList) {
            Node node = new Node();
            node.init(userInfo, maxChilds, comparator, clusterManager, this);
            waitAdd.put(node.getId(), node);
        }

        batchPut(waitAdd, flush);
    }

    /**
     * 批量插入缓存
     *
     * @param map   要批量插入的数据
     * @param flush 是否立即刷新
     */
    private void batchPut(Map<Integer, Node> map, boolean flush) {
        localCache.putAll(map);
        if (flush) {
            flush();
        }
    }

    /**
     * 初始化前调用，添加用户信息
     *
     * @param userInfoMap 要添加的用户信息
     * @param flush       是否立即刷新
     */
    public void addData(Map<Integer, UserInfo> userInfoMap, boolean flush) {
        addData(userInfoMap.values(), flush);
    }

    /**
     * 初始化，重新建立链接，重构缓存，数据量大的时候操作极慢，谨慎使用，当有3280条数据时（8层）大概需要10秒
     */
    public void init() {
        log.info("开始链接");

        //开始前必须将之前添加的数据flush
        flush();
        //将远程数据添加到本地
        localCache.putAll(userInfoMap);

        localCache.values().stream().filter(node -> UserInfo.exist(node.getParentId())).forEach(node -> {
            //从缓存中取出父级节点
            Node parent = convert(node.getParentId());

            if (parent == null) {
                log.warn("用户[{}]不存在", node.getParentId());
                return;
            }

            //根据缓存数据构建
            Node now = Node.build(node, maxChilds, comparator, clusterManager, this);

            parent.addNotFullChild(now, (t) -> null, false);
        });

        log.info("链接完毕");

        log.info("更新引用");
        localCache.values().stream().filter(node -> UserInfo.exist(node.getParentId())).forEach(node -> {
            if (node.getAllChilds().size() >= maxChilds) {
                Node parent = convert(node.getParentId());
                parent.moveToFullChild(node.getId(), false);
            }
        });
        //单独刷新缓存，将上述更改刷新进缓存
        flush();
        log.info("引用更新完毕");
    }

    /**
     * 创建一个根节点（没有任何关系的节点）
     *
     * @param root 根节点
     * @return 创建的节点信息，如果当前用户已经存在缓存那么将直接返回缓存中的用户而并不会创建新的
     */
    public UserInfo create(UserInfo root) {
        return readLockExec(t -> {
            Node node = getOrCreate(t, true);
            return node;
        }, root);
    }

    /**
     * 更新用户的销售额
     *
     * @param id          用户ID
     * @param salesVolume 更新的销售额
     * @return 当用户不存在时返回null，当用户存在时更新并返回传入的salesVolume
     */
    public BigDecimal update(int id, BigDecimal salesVolume) {
        return readLockExec(t -> {
            Node node = convert(id);
            if (node == null) {
                return null;
            }
            node.setSalesVolume(salesVolume);
            putCache(id, node, true);
            return salesVolume;
        }, null);
    }

    /**
     * 从缓存获取一个用户
     *
     * @param id 用户ID
     * @return 如果不存在返回null，否则返回该id对应的缓存中的用户
     */
    public UserInfo get(int id) {
        return this.convert(id);
    }

    /**
     * 为父级添加下级
     *
     * @param parent   父级节点
     * @param child    下级节点
     * @param function 插入成功回调，如果该回调失败则不会插入数据（可以在这里插入数据库），会将插入的子节点传入函数
     * @param layer    最多往下多少层，传入1表示只能挂到当前节点下边，传入2表示最多只能下挂到当前节点的子节点下面，以此类推
     * @return 如果父级未满则添加到当前父级，返回当前父级，如果当前已满则添加到父级的下级，返回添加后child的实际上
     * <p>
     * 级，返回null表示当前用户所有下级都满了，抛出{@link com.fruit.service.promotion.impl.FunctionException FunctionException}
     * <p>
     * 表示用户自定义函数执行失败，此时会回滚，并且抛出异常
     * @throws FunctionException 用户回调函数执行失败，此时数据不会插入缓存，并且会抛出该异常
     */
    public UserInfo addChild(UserInfo parent, UserInfo child, TransactionFunction<UserInfo, Object> function, int
            layer) throws FunctionException {
        return readLockExec(t -> {
            if (parent == null || child == null || !UserInfo.exist(parent.getId()) || !UserInfo.exist(child.getId())) {
                throw new IllegalArgumentException("参数错误");
            }

            Node pNode = getOrCreate(parent, true);
            Node cNode = getOrCreate(child, true);
//            下面的注释的部分会导致一些未知错误
//            //更新数据
//            pNode.init(parent, maxChilds, comparator, clusterManager, this);
//            cNode.init(child, maxChilds, comparator, clusterManager, this);
            pNode = pNode.addChild(cNode, function, layer);
            if (pNode == null) {
                log.warn("当前节点可能已经挂在到其节点了");
                return convert(convert(cNode.getId()).getParentId());
            }
            return pNode;
        }, null);
    }

    /**
     * 获取用户指定层数下的子节点集合
     *
     * @param uid   用户ID
     * @param layer 层数
     * @return 用户指定层数的子节点集合（只有该层，没有上层的）
     */
    public List<UserInfo> getLayerChilds(int uid, int layer) {
        return readLockExec(t -> {
            if (!UserInfo.exist(uid) || layer <= 0) {
                return Collections.emptyList();
            }
            Node node = convert(uid);
            if (node == null) {
                return Collections.emptyList();
            } else {
                return node.getAllNode(layer).stream().map(n -> (UserInfo) n).collect(Collectors.toList());
            }
        }, null);
    }

    /**
     * 获取当前用户的指定层数父级
     *
     * @param layer 层数
     * @param id    用户ID
     * @return 返回用户实际的上级，如果要获取15级但是只有10级那么返回的List里将只有10个，List中从0到最后依次是一级上级、二级上级到n级上级
     */
    public List<UserInfo> getParent(int layer, int id) {
        return readLockExec(LAYER -> {
            log.info("获取用户[{}]的[{}]级上级", id, LAYER);
            if (LAYER <= 0) {
                return Collections.emptyList();
            }
            Node node = convert(id);
            if (node == null || !UserInfo.exist(node.getParentId())) {
                log.info("用户[{}]不存在缓存", id);
                return Collections.emptyList();
            }

            List<UserInfo> parents = new ArrayList<>(LAYER);

            int parentId = node.getParentId();
            while (LAYER > 0) {
                LAYER--;
                if (!UserInfo.exist(parentId) || (node = convert(parentId)) == null) {
                    log.info("用户上级[{}]不存在", parentId);
                    break;
                }
                parents.add(node);
                parentId = node.getParentId();
            }
            log.info("用户[{}]上级列表为[{}]", id, parents);
            return parents;
        }, layer);
    }

    /**
     * 判断是否需要初始化
     *
     * @return 返回true表示已经未初始化
     */
    public boolean isInit() {
        return userInfoMap == null || userInfoMap.isEmpty();
    }

    /**
     * 从缓存中获取，如果不存在则创建并放入缓存
     *
     * @param userInfo 要获取的用户信息
     * @return 对应的缓存节点
     */
    private Node getOrCreate(UserInfo userInfo, boolean flush) {
        log.info("获取用户[{}]对应的节点，[{}]", userInfo, flush ? "刷新" : "不刷新");
        Node node = convert(userInfo.getId());
        if (node == null) {
            node = new Node();
            node.init(userInfo, maxChilds, comparator, clusterManager, this);
            node = node.writeLockExec(n -> {
                Node newNode = convert(userInfo.getId());
                if (newNode == null) {
                    putCache(n.getId(), n, flush);
                    newNode = n;
                }
                return newNode;
            }, node);
        }
        log.info("[{}]对应的节点是[{}]", userInfo, node);
        return node;
    }

    /**
     * 根据ID集合从缓存中取出一个Node集合
     *
     * @param list ID集合
     * @return 对应的Node集合
     */
    private List<Node> convert(Collection<Integer> list) {
        if (list == null || list.isEmpty()) {
            return Collections.emptyList();
        }
        return list.stream().map(this::convert).collect(Collectors.toList());
    }

    /**
     * 将ID转换为一个节点，优先从本地缓存取，而本地缓存取不到再从redis取
     *
     * @param id 用户ID
     * @return 对应的节点
     */
    private Node convert(int id) {
        if (!UserInfo.exist(id)) {
            return null;
        }
        Node node = localCache.get(id);
        if (node == null) {
            node = userInfoMap.get(id);
            if (node == null) {
                return null;
            }
        }
        return Node.build(node, maxChilds, comparator, clusterManager, this);
    }

    private synchronized Map<Integer, Node> getAllCache() {
        //防止远程数据覆盖本地数据，本地数据是最新的
        userInfoMap.forEach((k, v) -> {
            if (!localCache.containsKey(k)) {
                localCache.put(k, v);
            }
        });
        return localCache;
    }

    /**
     * 放入缓存
     *
     * @param id    缓存ID
     * @param node  缓存节点
     * @param flush 是否立即刷新
     */
    private void putCache(int id, Node node, boolean flush) {
        localCache.put(id, node);
        if (flush) {
            flush();
        }
    }

    /**
     * 删除缓存
     *
     * @param id 缓存ID
     */
    private void deleteCache(int id) {
        localCache.remove(id);
        userInfoMap.remove(id);
    }

    /**
     * 刷新缓存，同时能有一个线程调用
     */
    private synchronized void flush() {
        if (localCache.size() <= BATCH_NUM) {
            userInfoMap.putAll(localCache);
        } else {
            Map<Integer, List<Node>> result = localCache.values().stream().collect(Collectors.groupingBy(node -> node
                    .getId() / BATCH_NUM));
            result.values().stream().forEach(list -> {
                Map<Integer, Node> entry = new HashMap<>();
                list.stream().forEach(node -> entry.put(node.getId(), node));
                userInfoMap.putAll(entry);
            });
        }

        localCache.clear();
    }

    /**
     * 外部请勿调用
     *
     * @return 外部请勿调用，类内部使用
     */
    @Override
    public ReadWriteLock getLock() {
        return this.lock;
    }

    /**
     * 清空缓存
     */
    public void clear() {
        this.userInfoMap.clear();
        this.localCache.clear();
    }

    /**
     * 功能类；
     * <p>
     * 所有添加子节点的方法最终都应该调用{@link #addNoLock(Collection, Node, TransactionFunction, boolean) addNoLock}方法，用于集中管理！！！
     */
    @NoArgsConstructor
    private static class Node extends UserInfo implements LockExecFunction {
        private static transient String LOCK_NAME_PRE = CACHE_NAME + "_NodeLock_";
        /**
         * 子节点最大数量
         */
        private transient int maxChilds;
        /**
         * 本节点的数据读写锁
         */
        private transient ReadWriteLock lock;
        /**
         * 比较排序函数
         */
        private transient Comparator<UserInfo> comparator;
        /**
         * 分布式管理器
         */
        private transient ClusterManager clusterManager;
        /**
         * 树节点
         */
        private transient TreeCache treeCache;

        public static Node build(UserInfo userInfo, int maxChilds, Comparator<UserInfo> comparator, ClusterManager
                clusterManager, TreeCache treeCache) {
            Node node = new Node();

            node.init(userInfo, maxChilds, comparator, clusterManager, treeCache);
            return node;
        }

        /**
         * 初始化节点，用于将数据从Redis拉下来后构建对应的功能类
         *
         * @param userInfo       信息
         * @param maxChilds      子节点最大数量
         * @param comparator     比较器
         * @param clusterManager 分布式管理器
         * @param treeCache      TreeCache
         */
        public void init(UserInfo userInfo, int maxChilds, Comparator<UserInfo> comparator, ClusterManager
                clusterManager, TreeCache treeCache) {
            this.treeCache = treeCache;
            this.maxChilds = maxChilds;
            this.comparator = comparator;
            this.clusterManager = clusterManager;
            this.lock = clusterManager.getReadWriteLock(LOCK_NAME_PRE + Integer.valueOf(getId()));

            update(userInfo);
        }

        /**
         * 更新信息
         *
         * @param userInfo 信息来源
         */
        public void update(UserInfo userInfo) {
            setId(userInfo.getId());
            setParentId(userInfo.getParentId());
            setTime(userInfo.getTime());
            setSalesVolume(userInfo.getSalesVolume());
            setAllChilds(userInfo.getAllChilds());
            setFullChilds(userInfo.getFullChilds());
            setNotFullChilds(userInfo.getNotFullChilds());
            setActivityId(treeCache.activityId);
        }

        /**
         * 添加一个下级不满的下级节点
         *
         * @param node     下级节点
         * @param function 插入成功回调，如果该回调失败则不会插入数据（可以在这里插入数据库）
         * @param flush    是否立即刷新到redis，true表示立即刷新（主要用于初始化优化）
         * @return 返回true表示添加成功，返回false表示添加失败
         */
        public boolean addNotFullChild(Node node, TransactionFunction<UserInfo, Object> function, boolean flush) {
            log.debug("为节点[{}]添加一个未满的下级节点[{}]", this.getId(), node);
            return writeLockExec(self -> node.writeLockExec(t -> {
                //应对错误数据
                //本节点已满并且本节点不包含要添加的节点或者该节点存在父节点并且父节点不等于null
                if (t.isFull() && !t.getAllChilds().contains(node.getId())) {
                    log.warn("为节点[{}]添加一个未满的下级节点[{}]，执行中发现数据错误，当前节点已满并且不包含要添加的节点", t, node);
                    return false;
                } else if (UserInfo.exist(node.getParentId()) && node.getParentId() != t.getId()) {
                    log.warn("为节点[{}]添加一个未满的下级节点[{}]，执行中发现数据错误，当前要添加的节点已有父节点，父节点ID为：[{}]", t, node, node.getParentId());
                    return false;
                } else {
                    t.addNoLock(t.getNotFullChilds(), node, function, flush);
                    return true;
                }
            }, self), this);
        }

        /**
         * 添加一个下级已满的下级节点
         *
         * @param node     下级节点
         * @param function 插入成功回调，如果该回调失败则不会插入数据（可以在这里插入数据库）
         * @param flush    是否立即刷新到redis，true表示立即刷新（主要用于初始化优化）
         * @return 返回true表示添加成功，返回false表示添加失败
         */
        public boolean addFullChild(Node node, TransactionFunction<UserInfo, Object> function, boolean flush) {
            log.debug("为节点[{}]添加一个已满的下级节点[{}]", this.getId(), node);
            return writeLockExec(self -> {
                node.writeLockExec(t -> {
                    if (t.isFull() || UserInfo.exist(node.getParentId())) {
                        log.warn("为节点[{}]添加一个已满的下级节点[{}]，执行中发现数据错误", this.getId(), node);
                        return false;
                    } else {
                        t.addNoLock(t.getFullChilds(), node, function, flush);
                        return true;
                    }
                }, self);
                return true;
            }, this);
        }

        /**
         * 不加锁往集合添加数据，所有添加子节点的方法最终都应该调用该方法
         *
         * @param nodes    要添加数据的集合
         * @param node     要添加的数据
         * @param function 插入成功回调，如果该回调失败则不会插入数据（可以在这里插入数据库）
         * @param flush    是否立即刷新到redis，true表示立即刷新（主要用于初始化优化）
         * @throws FunctionException 用户回调函数执行失败，此时数据不会插入缓存，并且会抛出该异常
         */
        private void addNoLock(Collection<Integer> nodes, Node node, TransactionFunction<UserInfo, Object> function,
                               boolean flush) throws FunctionException {
            log.info("下挂节点[{}]到集合", node);
            node.setParentId(getId());
            getAllChilds().add(node.getId());
            nodes.add(node.getId());
            //更新缓存
            try {
                treeCache.putCache(node.getId(), node, flush);
                log.debug("执行用户下挂回调");
                function.invoke(node);
                log.debug("用户下挂回调执行成功");
                treeCache.putCache(getId(), this, flush);
            } catch (Throwable e) {
                log.warn("用户下挂回调执行失败，异常", e);
                //回滚
                treeCache.deleteCache(node.getId());
                throw new FunctionException(e);
            }
        }

        /**
         * 添加下级，如果下级已满则启动公排下挂
         *
         * @param node     要添加的下级
         * @param function 插入成功回调，如果该回调失败则不会插入数据（可以在这里插入数据库）
         * @param layer    最多往下多少层，传入2表示最多只能下挂到当前节点的子节点下面，以此类推
         * @return 添加的该下级的上级，返回null表示当前用户所有下级都满了
         * @throws FunctionException 用户回调函数执行失败，此时数据不会插入缓存，并且会抛出该异常
         */
        public Node addChild(Node node, TransactionFunction<UserInfo, Object> function, int layer) throws
                FunctionException {
            //锁住要添加的节点，防止其他线程修改
            return node.writeLockExec(newNode -> {
                //更新节点
                newNode = treeCache.convert(newNode.getId());
                //先判断当前node是否有上级
                //node已经有上级，可能是在其他服务挂载成功
                if (UserInfo.exist(newNode.getParentId())) {
                    Node parent = newNode.getParent();
                    //获取不到父节点信息，说明还没存进去
                    if (parent == null) {
                        log.warn("找不到节点[{}]的父节点", newNode);
                        //如果此时是其他节点正在更新肯定进不来，如果进来了发现父节点仍然不存在可能是数据错误
                        //或者其他未知原因父节点未被放入
                        log.warn("用户[{}]有父节点，但是父节点没有在缓存中，构建缓存", parent);
                        parent = build(treeCache.convert(newNode.getParentId()), maxChilds, comparator, clusterManager,
                                treeCache);
                        if (newNode.isFull()) {
                            parent.addNoLock(parent.getFullChilds(), newNode, function, true);
                        } else {
                            parent.addNoLock(parent.getNotFullChilds(), newNode, function, true);
                        }
                        return parent;
                    } else {
                        return parent;
                    }
                }

                //判断当前节点是否已经满了
                if (isFull()) {
                    log.info("当前节点[{}]下级已满，启动公排", this);
                    return add(newNode, function, layer);
                }


                //公排下挂
                return writeLockExec(newNodeRef -> {
                    int pid = this.getId();
                    if (isFull()) {
                        log.info("当前节点[{}]下级已满，启动公排下挂", pid);
                        //锁已经无用，先释放
                        lock.writeLock().unlock();
                        //调用公排下挂
                        Node parent;
                        try {
                            parent = add(newNodeRef, function, layer);
                            log.info("[{}]公排下挂到[{}]，实际下挂到了[{}]", newNodeRef, pid, parent);
                        } catch (Exception e) {
                            log.error("用户[{}]所有下级全满", this);
                            return null;
                        }
                        if (parent == null) {
                            log.warn("当前[{}]公排下挂到节点[{}]失败，重新下挂", newNodeRef, pid);
                            //下挂失败，重新下挂（有可能是下挂过程中节点变更，高并发下可能会出现该问题）
                            return addChild(newNodeRef, function, layer);
                        } else {
                            return parent;
                        }
                    } else {
                        log.info("当前节点[{}]，下级未满，可以直接下挂", pid);
                        //可以直接下挂，直接下挂到当前节点
                        Node parent = treeCache.convert(pid);

                        //下挂，更新引用
                        return newNodeRef.writeLockExec(p -> {
                            boolean flag;
                            if (newNodeRef.isFull()) {
                                flag = p.addFullChild(newNodeRef, function, true);
                            } else {
                                flag = p.addNotFullChild(newNodeRef, function, true);
                            }
                            if (flag) {
                                return p;
                            } else {
                                log.warn("直接下挂失败！！！");
                                throw new TreeException("直接下挂失败，状态异常");
                            }
                        }, parent);
                    }
                }, newNode);
            }, node);
        }

        /**
         * 公排下挂
         *
         * @param node     要下挂的节点
         * @param function 插入成功回调，如果该回调失败则不会插入数据（可以在这里插入数据库）
         * @param layer    最多往下多少层，传入2表示最多只能下挂到当前节点的子节点下面，以此类推
         * @return 下挂失败返回null（有可能已经在其他线程下挂成功了），下挂成功返回下挂的节点
         * @throws FunctionException 用户回调函数执行失败，此时数据不会插入缓存，并且会抛出该异常
         */
        public Node add(Node node, TransactionFunction<UserInfo, Object> function, int layer) throws FunctionException {
            //从第一层开始依次尝试下挂
            List<Node> nodes = Collections.singletonList(this);
            for (int i = 1; i < layer; i++) {
                //nodes不可能为空，如果为空上一级会计算
                nodes = getAllNode(nodes, 1);
                //这里允许有错误数据（即过期数据，后续会自动校验，所以不用加任何锁）
                List<Node> nodeList = nodes.stream().filter(n -> !n.isFull()).collect(Collectors.toList());
                if (nodeList.isEmpty()) {
                    continue;
                }
                nodeList.sort(comparator);
                Node n = nodeList.get(0);
                return n.writeLockExec(param -> {
                    //重新更新缓存
                    Node parent = treeCache.convert(n.getId());
                    if (parent.getAllChilds().size() >= maxChilds) {
                        //挂载失败，当前节点的子节点已满，更新引用
                        Node pNode = parent.getParent();
                        if (pNode != null) {
                            pNode.moveToFullChild(parent.getId(), true);
                        }
                        return null;
                    } else {
                        //挂载将要成功
                        return param.writeLockExec(p -> {
                            //重新更新缓存，判断当前节点是否已经有父节点（有可能是其他线程为其设置了）
                            Node child = treeCache.convert(param.getId());
                            if (!UserInfo.exist(child.getParentId())) {
                                //挂载成功
                                if (child.getAllChilds().size() <= child.maxChilds) {
                                    p.addNoLock(p.getNotFullChilds(), child, function, true);
                                } else {
                                    p.addNoLock(p.getFullChilds(), child, function, true);
                                }
                                log.info("节点[{}]挂载到[{}]下边挂载成功", child, p);
                                return p;
                            } else {
                                //挂载失败，可能是已经该节点在其他线程挂载到树中了
                                log.info("挂载失败，可能是已经该节点在其他线程挂载到树中了");
                                return null;
                            }
                        }, parent);
                    }
                }, node);
            }
            throw new TreeOverflowException("用户[" + this + "]的所有下级全满");
        }

        /**
         * 获取该节点的指定层数的下级
         *
         * @param layer 层数
         * @return 指定层数对应的下级列表
         */
        public List<Node> getAllNode(int layer) {
            return readLockExec(node -> getAllNode(Collections.singletonList(node), layer), this);
        }

        /**
         * 获取指定节点结合的指定层数的所有下级
         *
         * @param nodes 指定节点集合
         * @param layer 指定层数
         * @return 指定节点结合的指定层数的所有下级集合
         */
        private List<Node> getAllNode(List<Node> nodes, int layer) {
            if (layer <= 0) {
                return nodes;
            }
            List<Node> nodeList = new ArrayList<>();
            nodes.stream().forEach(node -> nodeList.addAll(node.getChilds()));
            return getAllNode(nodeList, --layer);
        }

        /**
         * 将节点从未满集合移动到已满集合
         *
         * @param id    要移动的节点ID
         * @param flush 是否立即刷新缓存
         */
        public void moveToFullChild(int id, boolean flush) {
            writeLockExec(n -> {
                if (getNotFullChilds().remove(n)) {
                    getFullChilds().add(n);
                    treeCache.putCache(getId(), this, flush);
                } else {
                    log.error("未满集合中不存在节点:[{}]", n);
                }
                return null;
            }, new Integer(id));
        }

        /**
         * 当前节点是否已满
         *
         * @return 返回true表示已经满了
         */
        public boolean isFull() {
            return getAllChilds().size() >= maxChilds;
        }

        /**
         * 获取所有一层子节点
         *
         * @return 所有子节点
         */
        public List<Node> getChilds() {
            return getAllChilds().stream().map(treeCache::convert).collect(Collectors.toList());
        }

        @Override
        public ReadWriteLock getLock() {
            return this.lock;
        }

        /**
         * 获取该节点对应的父节点
         *
         * @return 父节点，不存在时返回null
         */
        public Node getParent() {
            Node parent = null;
            if (UserInfo.exist(getParentId())) {
                parent = build(treeCache.convert(getParentId()), maxChilds, comparator, clusterManager, treeCache);
            }
            return parent;
        }
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    private static class CacheKey {
        private RedisBaseConfig config;
        private String cacheName;
    }
}
